package com.quectel.business.dms.application.access.accessor.im.impl;

import com.google.common.base.Preconditions;
import com.quectel.business.dms.application.ApplicationAccessConf;
import com.quectel.business.dms.application.access.accessor.im.AbstractIntelligentMonitorAccessor;
import com.quectel.business.dms.application.access.accessor.im.model.PlaybackPart;
import com.quectel.business.dms.application.access.accessor.im.model.SearchMapReq;
import com.quectel.business.dms.application.access.accessor.im.model.SearchMapResp;
import com.quectel.business.dms.application.access.accessor.im.model.StreamResp;
import com.quectel.business.dms.application.access.basemodel.ApplicationOriginDevice;
import com.quectel.business.dms.device.DeviceBusiness;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.application.service.ApplicationService;
import com.quectel.core.module.device.dto.DeviceCommandTemplateDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.DeviceTypeService;
import com.quectel.sdk.simulation.SimulationClientBuilder;
import com.quectel.sdk.simulation.basemodel.SimulationDevice;
import com.quectel.sdk.simulation.monitor.MonitorClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2021/12/1 9:37 上午
 */
@Component
@Slf4j
public class SimulationMonitorAccessorImpl extends AbstractIntelligentMonitorAccessor {

    @DubboReference
    private DeviceTypeService deviceTypeService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private ApplicationService applicationService;
    @Autowired
    private DeviceBusiness deviceBusiness;


    @Override
    public boolean initApplication(ApplicationDto application) {
        return syncOrRegisterDevices(application, null) && subscribeEvents(application);
    }


    @Override
    public boolean syncOrRegisterDevices(ApplicationDto application, List<ApplicationOriginDevice> devices) {
        final Date currentDate = new Date();

        ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, application.getAccessConf());

        try {
            Preconditions.checkNotNull(conf);
            MonitorClient monitorClient = SimulationClientBuilder.builder()
                    .url(conf.getUrl())
                    .accessKey(conf.getAccessKey())
                    .accessSecret(conf.getAccessSecret())
                    .build(MonitorClient.class);

            List<SimulationDevice> syncDevices = monitorClient.getMonitors();
            List<DeviceDto> deviceDtos = syncDevices.parallelStream()
                    .filter(o -> deviceService.selectByUniqueId(o.getUniqueId(), application.getTenantId()) == null)
                    .map(o -> {
                        DeviceDto deviceDto = new DeviceDto();
                        deviceDto.setUniqueId(o.getUniqueId());
                        deviceDto.setImei(o.getImei());
                        deviceDto.setName(o.getName());
                        deviceDto.setLatitude(o.getLatitude());
                        deviceDto.setLongitude(o.getLongitude());
                        deviceDto.setCreateTime(currentDate);
                        fill(deviceDto, application);
                        return deviceDto;
                    }).collect(Collectors.toList());

            deviceService.saveBatch(deviceDtos);
            return true;
        } catch (Exception e) {
            log.error("模拟平台 监控同步 syncOrRegisterDevices 异常", e);
        }
        return false;
    }

    @Override
    public boolean subscribeEvents(ApplicationDto application) {
        return true;
    }

    @Override
    public boolean sendCmd(DeviceDto deviceDto, DeviceCommandTemplateDto deviceCommandTemplateDto, Map<String, Object> params, Long cmdId) {
        return false;
    }


    @Override
    public List<StreamResp> getStreamUrls(List<DeviceDto> monitors) {
        List<String> result = new ArrayList<>();

        for (DeviceDto monitor : monitors) {
            ApplicationDto applicationDto = applicationService.selectById(monitor.getApplicationId());
            Preconditions.checkNotNull(applicationDto);

            ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                    .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, applicationDto.getAccessConf());

            try {
                Preconditions.checkNotNull(conf);
                MonitorClient monitorClient = SimulationClientBuilder.builder()
                        .url(conf.getUrl())
                        .accessKey(conf.getAccessKey())
                        .accessSecret(conf.getAccessSecret())
                        .build(MonitorClient.class);
                result.add(monitorClient.getStreamUrls(Arrays.asList(monitor.getUniqueId())).get(0));
            } catch (Exception e) {
                log.error("模拟平台 监控获取流 异常", e);
                result.add(null);
            }
        }

        return result.stream().map(v -> {
            if (v == null) {
                return null;
            }
            return new StreamResp(v, StreamResp.StreamType.HLS264);
        }).collect(Collectors.toList());
    }

    @Override
    public List<PlaybackPart> getPlaybackParts(DeviceDto monitor, Date startTime, Date endTime) {
        String[] urls = new String[]{
                "https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo.mp4",
                "rtmp://192.168.25.85/live/livestream"
        };

        ArrayList<PlaybackPart> result = Lists.newArrayList();
        PlaybackPart playbackPart = new PlaybackPart();
        playbackPart.setStartTime(startTime);
        playbackPart.setEndTime(endTime);
        playbackPart.setStreamUrl(urls[new SecureRandom().nextInt(urls.length)]);
        result.add(playbackPart);
        return result;
    }

    @Override
    public SearchMapResp searchMap(SearchMapReq req) {

        return new SearchMapResp();
    }
}
